#include "FreeRTOS.h"
#include "task.h"
#include "stm32f4xx_hal.h"
#include "stm32f4xx_hal_gpio.h"
#include "./stm32f401_pico_uart.h"
#include "./stm32f401_pico_i2c.h"
#include <stdio.h>
#include <string.h>
#include "bus/swi2c.h"
#include "bus/swi2c_ex.h"

// 任务句柄与全局变量
TaskHandle_t i2c_task_handle = NULL;
uint8_t i2c_task_running = 1;      // I2C任务运行状态标志


#ifndef OUTPUT
#define OUTPUT 0
#endif

#ifndef INPUT
#define INPUT 1
#endif

// 硬件定义
#define AT24C02_ADDR 0x50         // EEPROM设备地址
#define EEPROM_WRITE_ADDR 0x08    // 写入的目标地址
#define I2C_SCL_PIN GPIO_PIN_8    // PB8作为SCL
#define I2C_SDA_PIN GPIO_PIN_9    // PB9作为SDA

// 全局变量
swi2c_t swi2c;                    // 软件I2C对象
uint8_t write_data = 0xBB;         // 待写入的数据

void delay_us(int us)
{
	int curr_systick_timer_val = 0;     /* 当前滴答定时器的计数值 */
	int curr_systick_interrupt_cnt = 0; /* 当前滴答定时器中断计数值 */
	int delay_us_timer_cnt = 0;         /* 延时 us(参数) 时间对应的滴答定时器计数值 */
	int timeout_systick_timer_val = 0;  /* 延时结束时刻滴答定时器的计数值 */
	int timer_cnt_per_ms = 0;           /* 1ms 时间对应的滴答定时器的计数值 */
	int timer_cnt_per_us = 0;           /* 1us 时间对应的滴答定时器的计数值 */

	/**
	 * 假设系统时钟是 84M
	 * 1s  时间, 滴答定时器计数值是 84,000,000
	 * 1ms 时间, 滴答定时器计数值是 84,000
	 * 1us 时间, 滴答定时器计数值是 84
	 */
	timer_cnt_per_ms = SystemCoreClock / (1000U / uwTickFreq);
	timer_cnt_per_us = timer_cnt_per_ms / 1000U;

	curr_systick_timer_val = SysTick->VAL;
	curr_systick_interrupt_cnt = HAL_GetTick();
	delay_us_timer_cnt = us * timer_cnt_per_us;

	if (delay_us_timer_cnt > curr_systick_timer_val) {
		while (HAL_GetTick() == curr_systick_interrupt_cnt) {
		}

		timeout_systick_timer_val = timer_cnt_per_ms + curr_systick_timer_val - delay_us_timer_cnt;

		while (timeout_systick_timer_val < SysTick->VAL) {
		}
	} else {
		timeout_systick_timer_val = curr_systick_timer_val - delay_us_timer_cnt;
		while (timeout_systick_timer_val < SysTick->VAL && HAL_GetTick() == curr_systick_interrupt_cnt) {
		}
	}
}

// I2C引脚控制函数
void _scl_set_val(int val)
{
    HAL_GPIO_WritePin(GPIOB, I2C_SCL_PIN, val);
}

void _sda_set_dir(int dir)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    GPIO_InitStruct.Pin = I2C_SDA_PIN;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Mode = (dir == INPUT) ? GPIO_MODE_INPUT : GPIO_MODE_OUTPUT_PP;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}

void _sda_set_val(int val)
{
    HAL_GPIO_WritePin(GPIOB, I2C_SDA_PIN, val);
}

int _sda_get_val()
{
    return HAL_GPIO_ReadPin(GPIOB, I2C_SDA_PIN);
}

// I2C GPIO初始化
void I2C_GPIO_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    // 使能GPIOB时钟
    __HAL_RCC_GPIOB_CLK_ENABLE();

    // 初始化SCL和SDA引脚为推挽输出
    GPIO_InitStruct.Pin = I2C_SCL_PIN | I2C_SDA_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL; // 需外部上拉电阻
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}

// I2C初始化
void I2C_Init(void)
{
    // 配置软件I2C参数
    swi2c.cfg.fix.speed = 100000; // 100kHz通信速率
    swi2c.ops.usleep = delay_us;
    swi2c.ops.scl_set_val = _scl_set_val;
    swi2c.ops.sda_set_dir = _sda_set_dir;
    swi2c.ops.sda_set_val = _sda_set_val;
    swi2c.ops.sda_get_val = _sda_get_val;
}

// I2C读操作封装
int i2c_read_from_eeprom(uint8_t device_address, uint8_t* memory_address, uint8_t* buffer, uint32_t length)
{
    printf("测试2\r\n");
	return i2c_r8v8_read(&swi2c, device_address, memory_address, buffer, length);
}

// I2C写操作封装
int i2c_write_to_eeprom(uint8_t dev_addr, uint8_t mem_addr, uint8_t* data, uint32_t len)
{
    printf("测试1\r\n");
    return i2c_r8v8_write(&swi2c, dev_addr, &mem_addr, data, len);
    // return 0;
}

// I2C任务：向EEPROM的0x00地址写入字节'a'
void I2C_Task(void *pvParameters)
{
    printf("任务开始3\r\n");
    I2C_GPIO_Init();
    printf("EEPROM写入测试\r\n");
    int ret;
    uint8_t mem_addr = EEPROM_WRITE_ADDR; // 目标地址0x00
    uint8_t read_data = 0;
    
    // 确保I2C初始化
    I2C_Init();
    
    
        // 只有当运行标志为1时才执行I2C写操作
        if (i2c_task_running) 
        {
            printf("开始I2C写入...\r\n");
            
            // 写入数据（添加超时处理）          
            ret = i2c_write_to_eeprom(AT24C02_ADDR, mem_addr, &write_data, 1);
            printf("I2C写入完成，结果: %s\r\n", ret == 0 ? "成功" : "失败");
            
            // 2. 写入后延时5ms（满足AT24C02的写入周期要求）
            vTaskDelay(pdMS_TO_TICKS(5));
            
            // 3. 执行读取操作（无论写入是否成功，都尝试读取）
            printf("开始I2C读取...\r\n");
            // 调用读取函数：从AT24C02的0x00地址读取1字节数据到read_data
            ret = i2c_read_from_eeprom(AT24C02_ADDR, &mem_addr, &read_data, 1);
            printf("I2C读取完成，结果: %s\r\n", ret == 0 ? "成功" : "失败");
            
            // 4. 打印读取到的数据（若读取成功）
            if (ret == 0)
            {
                printf("从EEPROM地址0x%02X读取到数据: 0x%02X\r\n",
                       mem_addr, read_data);
            }
            else
            {
                printf("读取失败，无法获取数据\r\n");
            }
        
        
        vTaskDelay(pdMS_TO_TICKS(1000)); // 任务周期1秒
    }
}